package com.jvxb.manage.livable.service.dbDeploy.impl;

import com.jvxb.common.base.entity.WorkTask;
import com.jvxb.common.constants.DbConstants;
import com.jvxb.common.utils.IPUtil;
import com.jvxb.common.utils.WorkTaskUtil;
import com.jvxb.manage.livable.entity.AssetsAgentHost;
import com.jvxb.manage.livable.entity.DbDeployInfo;
import com.jvxb.manage.livable.entity.DbDeployInstance;
import com.jvxb.manage.livable.service.dbDeploy.RedisDeployService;
import com.jvxb.manage.livable.service.dbDeploy.impl.BaseDeployServiceImpl;
import com.jvxb.manage.livable.vo.WorkOrderOperateVo;
import lombok.extern.log4j.Log4j2;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author jvxb
 * @since 2022-01-10
 */
@Log4j2
@Service(DbConstants.REDIS + DbConstants.DEPLOY_SERVICE)
public class RedisDeployServiceImpl extends BaseDeployServiceImpl implements RedisDeployService {

    @Override
    public List<AssetsAgentHost> checkAndGetResource(DbDeployInfo dbDeployInfo, boolean getResource) {
        if (dbDeployInfo.getArchType().equals(DbConstants.ARCH_TYPE_CLUSTER)) {
            throw new RuntimeException("当前仅支持redis单机版");
        }
        return super.checkAndGetResource(dbDeployInfo, getResource);
    }

    @Override
    @Async("asyncDeployExecutor")
    public void deploy(DbDeployInfo dbDeployInfo, WorkOrderOperateVo workOrderOperateVo) {
        log.info("开始部署" + dbDeployInfo.getDbType());
        try {
            //1）选择部署机器
            List<DbDeployInstance> deployInstances = getDbDeployInstances(dbDeployInfo);
            log.info(dbDeployInfo.getWorkOrderId() + "部署机器：" + deployInstances);
            //2）执行部署作业
            for (DbDeployInstance deployInstance : deployInstances) {
                executeDeployTask(deployInstance);
            }
            //3）初始化集群
            initRedisCluster(dbDeployInfo, deployInstances);
            //4）部署成功后的操作：保存集群实例数据、修改工单状态等
            deploySuccess(dbDeployInfo, workOrderOperateVo);
        } catch (Exception e) {
            //部署失败后的操作
            log.error("MySQL执行部署异常，工单id=" + dbDeployInfo.getWorkOrderId(), e);
            deployFail(dbDeployInfo, e.getMessage());
            //此处有可能需要回滚实例，目前略过
        }
        log.info(dbDeployInfo.getDbType() + "部署完成");
    }

    private void executeDeployTask(DbDeployInstance deployInstance) throws Exception {
        //可使用（二进制包/docker）部署，此处统一使用docker快速部署。
        Integer mysqlDeployWorkId = Integer.valueOf(sysDictService.getUniValueByGroupAndKey("db_deploy", "mysql_deploy_work_id", "1"));
        String mysqlDeployCmd = getRedisDeployCmd(deployInstance.getPort(), deployInstance.getVersion());
        WorkTask workTask = new WorkTask(mysqlDeployWorkId, deployInstance.getHost(), mysqlDeployCmd);
        WorkTaskUtil.run(workTask);
        //检测部署是否成功
        if (IPUtil.isPortUsed(deployInstance.getHost(), Integer.valueOf(deployInstance.getPort()))) {
            deployInstance.setDeployStatus(DbDeployInstance.DEPLOY_STATUS_SUCCESS);
        } else {
            deployInstance.setDeployStatus(DbDeployInstance.DEPLOY_STATUS_ERROR);
        }
        deployInstanceService.updateById(deployInstance);
    }

    private void initRedisCluster(DbDeployInfo dbDeployInfo, List<DbDeployInstance> deployInstances) {
        //构建主从等
        if (deployInstances.size() == 1) {
            deployInstances.get(0).setRole(DbConstants.ROLE_MASTER);
            deployInstanceService.saveOrUpdate(deployInstances.get(0));
        }
    }

    private String getRedisDeployCmd(String port, String version) {
        String confCmd = String.format("mkdir -p /docker/redis/%s/conf\n" +
                        "chmod 755 /docker/redis/%s/conf\n" +
                        "cat > /docker/redis/%s/conf/redis.conf <<END\n" +
                        "%s\n" +
                        "END\n" +
                        "chmod 644 /docker/redis/%s/conf/redis.conf\n",
                port, port, port, getDefaultRedisConf(), port);
        String deployCmd = String.format("docker run -p %s:6379 " +
                        "--name redis%s " +
                        "--restart=unless-stopped " +
                        "-v /docker/redis/%s/conf/redis.conf:/etc/redis/redis.conf " +
                        "-v /docker/redis/%s/data:/data " +
                        "-d redis:%s redis-server /etc/redis/redis.conf",
                port, port, port, port, version);
        return confCmd + "\n" + deployCmd;
    }

    private String getDefaultRedisConf() {
        return "protected-mode no\n" +
                "port 6379\n" +
                "tcp-backlog 511\n" +
                "timeout 0\n" +
                "tcp-keepalive 300\n" +
                "daemonize no\n" +
                "supervised no\n" +
                "pidfile /var/run/redis_6379.pid\n" +
                "loglevel notice\n" +
                "logfile \"\"\n" +
                "databases 16\n" +
                "always-show-logo yes\n" +
                "save 900 1\n" +
                "save 300 10\n" +
                "save 60 10000\n" +
                "stop-writes-on-bgsave-error yes\n" +
                "rdbcompression yes\n" +
                "rdbchecksum yes\n" +
                "dbfilename dump.rdb\n" +
                "dir ./\n" +
                "slave-serve-stale-data yes\n" +
                "slave-read-only yes\n" +
                "repl-diskless-sync no\n" +
                "repl-diskless-sync-delay 5\n" +
                "repl-disable-tcp-nodelay no\n" +
                "slave-priority 100\n" +
                "lazyfree-lazy-eviction no\n" +
                "lazyfree-lazy-expire no\n" +
                "lazyfree-lazy-server-del no\n" +
                "slave-lazy-flush no\n" +
                "appendonly yes\n" +
                "appendfilename \"appendonly.aof\"\n" +
                "appendfsync everysec\n" +
                "no-appendfsync-on-rewrite no\n" +
                "auto-aof-rewrite-percentage 100\n" +
                "auto-aof-rewrite-min-size 64mb\n" +
                "aof-load-truncated yes\n" +
                "aof-use-rdb-preamble no\n" +
                "lua-time-limit 5000\n" +
                "slowlog-log-slower-than 10000\n" +
                "slowlog-max-len 128\n" +
                "latency-monitor-threshold 0\n" +
                "notify-keyspace-events \"\"\n" +
                "hash-max-ziplist-entries 512\n" +
                "hash-max-ziplist-value 64\n" +
                "list-max-ziplist-size -2\n" +
                "list-compress-depth 0\n" +
                "set-max-intset-entries 512\n" +
                "zset-max-ziplist-entries 128\n" +
                "zset-max-ziplist-value 64\n" +
                "hll-sparse-max-bytes 3000\n" +
                "activerehashing yes\n" +
                "client-output-buffer-limit normal 0 0 0\n" +
                "client-output-buffer-limit slave 256mb 64mb 60\n" +
                "client-output-buffer-limit pubsub 32mb 8mb 60\n" +
                "hz 10\n" +
                "aof-rewrite-incremental-fsync yes\n";
    }

}
